package cn.eoeit.alone.phoneImport.db;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import cn.eoeit.alone.phoneImport.util.LogUtil;


import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;


/**
 * @author Jason Liu
 *
 */
public abstract class AbstractDatabaseAgent {
    private static final String TAG = LogUtil.getTag(AbstractDatabaseAgent.class);

    private final Lock mDbLock = new ReentrantLock();
    
    protected abstract class SqlTask<T> {
        public SQLiteDatabase db;
        private List<Cursor> cursors = new ArrayList<Cursor>();
        private List<SQLiteStatement> statements = new ArrayList<SQLiteStatement>();

        private boolean needStopWatch = false;
        private String stopName = "";
        private String sql = "";
        private String[] selectionArgs = null;
 
        protected abstract T doExecute();
        
        public SqlTask() {
        }

        public SqlTask(String stopName) {
            this.stopName = stopName;
            //needStopWatch = true;
        }

        protected Cursor rawQuery(String sql, String... selectionArgs) {
            if (needStopWatch) {
                StringBuilder builder = new StringBuilder();
                if (selectionArgs != null) {
                    for (Object arg : selectionArgs) {
                        builder.append(arg).append(", ");
                    }
                }
                LogUtil.i(TAG, "QUERY SQL: " + sql + "\nARGS: " + builder);
            }

            //Sanitiize the SQL. This is needed so that any ' are escaped
            //TODO: it will cause SQL syntax error issue. 
            //String sqlSanitized=sql.replaceAll("'", "''");
            if (needStopWatch) {
                this.sql = sql;
                this.selectionArgs = selectionArgs;
            }

            Cursor cursor = db.rawQuery(sql, selectionArgs);
//            LogUtil.i(TAG, "涓?叡寰楀埌锛?+cursor.getColumnCount()+"鏉℃暟鎹?);
            cursors.add(cursor);
            return cursor;
        }

        protected boolean execSQL(String sql) {
            return execSQL(sql);
        }
        
        protected SQLiteStatement compileStatement(String sql) {
            SQLiteStatement statement = db.compileStatement(sql);
            statements.add(statement);
            return statement;
        }

        protected boolean execSQL(String sql, Object... bindArgs) {
            boolean success = false;
            try {
                if (bindArgs == null) {
                    if (needStopWatch) {
                        LogUtil.d(TAG, "EXECUTE SQL: " + sql);
                    }
                    db.execSQL(sql);
                } else {
                    if (needStopWatch) {
                        StringBuilder builder = new StringBuilder();
                        for (Object arg : bindArgs) {
                            builder.append(arg).append(", ");
                        }
                        LogUtil.d(TAG, "EXECUTE SQL: " + sql + "\nARGS: " + builder);
                    }
                    db.execSQL(sql, bindArgs);
                }

                success = true;
            } catch (SQLException e) {
                LogUtil.e(TAG, "SQL: \n" + sql.toString(), e);
            }
            return success;
        }

        private void closeResources() {
            for (Iterator<Cursor> iterator = cursors.iterator(); iterator.hasNext();) {
                Cursor cursor = (Cursor) iterator.next();
                cursor.close();
                iterator.remove();
            }
            
            for (Iterator<SQLiteStatement> iterator = statements.iterator(); iterator.hasNext();) {
                SQLiteStatement statement = (SQLiteStatement) iterator.next();
                statement.close();
                iterator.remove();
            }
        }
        
        public void closeDb() {
            db.close();
        }
        
        public T execute() {
            T t = null;
            long start = System.nanoTime();
            mDbLock.lock();
            try {
                db = openSQLiteDatabase();
                t = doExecute();
            } catch (Exception e) {
                LogUtil.e(TAG, e.getMessage(), e);
            } finally {
                try {
                    closeResources();
                } catch (Exception e) {
                    LogUtil.e(TAG, e.getMessage(), e);
                }
                try {
                    if (db != null) {
                        db.close();
                    }
                } catch (Exception e) {
                    LogUtil.e(TAG, e.getMessage(), e);
                }

                mDbLock.unlock();

                try {
                    if (needStopWatch) {
                        long duration = (System.nanoTime() - start) / 1000000L;
                        StringBuffer strOut = new StringBuffer();
                        strOut.append(">>> SqlExec Stopwatch >>>")
                                .append(stopName)
                                .append(": ")
                                .append(duration)
                                .append(" ms : ")
                                .append(sql.replaceAll("\n", " "))
                                .append(" : ");
                        if (selectionArgs != null) {
                            for (int i = 0; i < selectionArgs.length; i++) {
                                strOut.append("[").append(selectionArgs[i]).append("]");
                            }
                        }
                        LogUtil.i(TAG, strOut.toString());
                    }
                } catch (Exception e) {
                    LogUtil.e(TAG, "", e);
                }
            }
            
            return t;
        }
    }

    protected abstract SQLiteDatabase openSQLiteDatabase();
    
    protected String getSql(String fomatSql, String[] columes) {
        if (columes == null || columes.length == 0) {
            return fomatSql;
        }
        
        if (fomatSql.contains("[COLUMES]")) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < columes.length; i++) {
                if (i > 0) {
                    builder.append(", ");
                }
                builder.append(columes[i]);
            }
            fomatSql = fomatSql.replace("[COLUMES]", builder.toString());
        }
        
        if (fomatSql.contains("[ALL_?]")) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < columes.length; i++) {
                if (i > 0) {
                    builder.append(", ");
                }
                builder.append("?");
            }
            
            fomatSql = fomatSql.replace("[ALL_?]", builder.toString());
        }
        LogUtil.i(TAG, "getSql="+fomatSql);
        return fomatSql;
    }
}
